//
// Created by jack on 2021/2/6.
//

#include "weilapb_defines.h"

#include <WL.Friend.pb.h>
#include <WL.Service.pb.h>
#include <pb_decode.h>

#include "weilapb_datafuns.h"

#include "weilapb_commondec.h"
#include "weilapb_error.h"
#include "weilapb_internal.h"

void* weilapb_decodeSubMsgFriendInfo(pb_istream_t* stream, const pb_field_t* field) {
    WL_Friend_FriendInfo wlFriendFriendInfo = WL_Friend_FriendInfo_init_zero;
    PBLinkItem*          pPbLinkItem        = PB_NULL;
    pPbLinkItem                             = (PBLinkItem*)PB_ALLOC(sizeof(PBLinkItem) + sizeof(PBFriendInfo));
    if (pPbLinkItem) {
        PBFriendInfo* pInfo;
        PBFieldData   remarkField;
        PBFieldData   labelField;
        PBFieldData   descField;
        PBFieldData   extentionField;

        pPbLinkItem->dataSize = sizeof(PBFileInfo);
        pInfo                 = (PBFriendInfo*)pPbLinkItem->data;

        weilapb_initDecDataItem(&remarkField, PB_DATA_TYPE_FIXED_SIZE_STRING, MAX_NORMAL_STRING_LEN, pInfo->remark);
        weilapb_setDecCallback(&remarkField, &wlFriendFriendInfo.remark, PB_NULL);

        weilapb_initDecDataItem(&labelField, PB_DATA_TYPE_FIXED_SIZE_STRING, MAX_SHORT_STRING_LEN, pInfo->label);
        weilapb_setDecCallback(&labelField, &wlFriendFriendInfo.label, PB_NULL);

        weilapb_initDecDataItem(&descField, PB_DATA_TYPE_FIXED_SIZE_STRING, MAX_LONG_STRING_LEN, pInfo->desc);
        weilapb_setDecCallback(&descField, &wlFriendFriendInfo.desc, PB_NULL);

        weilapb_initDecDataItem(
            &extentionField, PB_DATA_TYPE_FIXED_SIZE_STRING, MAX_NORMAL_STRING_LEN, pInfo->extension);
        weilapb_setDecCallback(&extentionField, &wlFriendFriendInfo.extension, PB_NULL);

        if (pb_decode(stream, WL_Friend_FriendInfo_fields, &wlFriendFriendInfo)) {
            if (wlFriendFriendInfo.has_userId) {
                pInfo->userId = wlFriendFriendInfo.userId;
            }

            if (wlFriendFriendInfo.has_tts) {
                pInfo->tts = wlFriendFriendInfo.tts;
            }

            if (wlFriendFriendInfo.has_status) {
                pInfo->status = wlFriendFriendInfo.status;
            }

            if (wlFriendFriendInfo.has_locationShare) {
                pInfo->locationShared = wlFriendFriendInfo.locationShare;
            }

            if (wlFriendFriendInfo.has_shieldStatus) {
                pInfo->recvStatus = wlFriendFriendInfo.shieldStatus;
            }
        } else {
            PB_FREE(pPbLinkItem);
            pPbLinkItem = PB_NULL;
        }
    }

    return pPbLinkItem;
}

PBWeilaMsg* weilapb_decodeGetFriendInfoRsp(const PB_UINT8* pData, PB_UINT32 dataSize) {
    WL_Service_ServiceMessage serviceMessage = WL_Service_ServiceMessage_init_zero;
    pb_istream_t              istream;
    PBWeilaMsg*               pWeilaMsg = PB_ALLOC(sizeof(PBWeilaMsg) + sizeof(PBGetFriendInfoRsp));

    istream = pb_istream_from_buffer(pData, dataSize);

    if (pWeilaMsg) {
        PBFieldData         friendInfoListField;
        PBFieldData         userInfoListField;
        PBGetFriendInfoRsp* pPbGetFriendInfoRsp;

        pPbGetFriendInfoRsp    = (PBGetFriendInfoRsp*)pWeilaMsg->pContent;
        pWeilaMsg->contentSize = sizeof(PBGetFriendInfoRsp);

        weilapb_initDecDataItem(
            &friendInfoListField, PB_DATA_TYPE_LINK_SUBMSG, 0, &pPbGetFriendInfoRsp->friendInfoList);
        weilapb_setDecCallback(
            &friendInfoListField, &serviceMessage.friendMessage.rspGetFriendInfo.friendInfos, PB_NULL);
        friendInfoListField.decSubMsg = weilapb_decodeSubMsgFriendInfo;

        weilapb_initDecDataItem(&userInfoListField, PB_DATA_TYPE_LINK_SUBMSG, 0, &pPbGetFriendInfoRsp->userInfoList);
        weilapb_setDecCallback(&userInfoListField, &serviceMessage.friendMessage.rspGetFriendInfo.userInfos, PB_NULL);
        userInfoListField.decSubMsg = weilapb_decodeSubMsgUserInfo;

        if (weilapb_decodeWeilaMsg(pWeilaMsg, &istream, &serviceMessage)) {
            weilapb_addRecyclePointer(pWeilaMsg, RECYCLE_PTR_LINK, &pPbGetFriendInfoRsp->friendInfoList);
            weilapb_addRecyclePointer(pWeilaMsg, RECYCLE_PTR_LINK, &pPbGetFriendInfoRsp->userInfoList);
            if (serviceMessage.friendMessage.rspGetFriendInfo.has_latestUpdated) {
                pPbGetFriendInfoRsp->latestTimestamp = serviceMessage.friendMessage.rspGetFriendInfo.latestUpdated;
            }
            return pWeilaMsg;
        }

        weilapb_freePBLinkList(&pPbGetFriendInfoRsp->friendInfoList);
        weilapb_freePBLinkList(&pPbGetFriendInfoRsp->userInfoList);
        weilapb_error(ERR_DECODE, "decode msg data fail");
        PB_FREE(pWeilaMsg);
        pWeilaMsg = PB_NULL;
    } else {
        weilapb_error(ERR_OUT_OF_MEMORY, "allocate weila msg failed");
    }

    return pWeilaMsg;
}

PBWeilaMsg* weilapb_decodeGetFriendUserInfoRsp(const PB_UINT8* pData, PB_UINT32 dataSize) {
    WL_Service_ServiceMessage serviceMessage = WL_Service_ServiceMessage_init_zero;
    pb_istream_t              istream;
    PBWeilaMsg*               pWeilaMsg = PB_ALLOC(sizeof(PBWeilaMsg) + sizeof(PBGetFriendUserInfoRsp));

    istream = pb_istream_from_buffer(pData, dataSize);

    if (pWeilaMsg) {
        PBGetFriendUserInfoRsp* pPbGetFriendUserInfoRsp;
        PBFieldData             userInfoListField;
        pWeilaMsg->contentSize  = sizeof(PBGetFriendUserInfoRsp);
        pPbGetFriendUserInfoRsp = (PBGetFriendUserInfoRsp*)pWeilaMsg->pContent;
        weilapb_initDecDataItem(&userInfoListField, PB_DATA_TYPE_LINK_SUBMSG, 0, pPbGetFriendUserInfoRsp);
        weilapb_setDecCallback(
            &userInfoListField, &serviceMessage.friendMessage.rspGetFriendUserInfo.userInfos, PB_NULL);
        userInfoListField.decSubMsg = weilapb_decodeSubMsgUserInfo;

        if (weilapb_decodeWeilaMsg(pWeilaMsg, &istream, &serviceMessage)) {
            weilapb_addRecyclePointer(pWeilaMsg, RECYCLE_PTR_LINK, pPbGetFriendUserInfoRsp);
            return pWeilaMsg;
        }

        weilapb_freePBLinkList(pPbGetFriendUserInfoRsp);
        weilapb_error(ERR_DECODE, "decode msg data fail");
        PB_FREE(pWeilaMsg);
        pWeilaMsg = PB_NULL;
    } else {
        weilapb_error(ERR_OUT_OF_MEMORY, "allocate weila msg failed");
    }

    return pWeilaMsg;
}

void* weilapb_decodeSubMsgFriendInviteInfo(pb_istream_t* stream, const pb_field_t* field) {
    WL_Friend_FriendInviteInfo wlFriendFriendInviteInfo = WL_Friend_FriendInviteInfo_init_zero;
    PBLinkItem*                pPbLinkItem              = PB_NULL;
    pPbLinkItem = (PBLinkItem*)PB_ALLOC(sizeof(PBLinkItem) + sizeof(PBFriendInviteInfo));
    if (pPbLinkItem) {
        PBFieldData         detailField;
        PBFriendInviteInfo* pInfo;

        pPbLinkItem->dataSize = sizeof(PBFriendInviteInfo);
        pInfo                 = (PBFriendInviteInfo*)pPbLinkItem->data;

        weilapb_initDecDataItem(&detailField, PB_DATA_TYPE_FIXED_SIZE_STRING, MAX_NORMAL_STRING_LEN, pInfo->detail);
        weilapb_setDecCallback(&detailField, &wlFriendFriendInviteInfo.detail, PB_NULL);

        if (pb_decode(stream, WL_Friend_FriendInviteInfo_fields, &wlFriendFriendInviteInfo)) {
            if (wlFriendFriendInviteInfo.has_inviterId) {
                pInfo->inviterId = wlFriendFriendInviteInfo.inviterId;
            }

            if (wlFriendFriendInviteInfo.has_inviteeId) {
                pInfo->inviteeId = wlFriendFriendInviteInfo.inviteeId;
            }

            if (wlFriendFriendInviteInfo.has_status) {
                pInfo->status = wlFriendFriendInviteInfo.status;
            }

            if (wlFriendFriendInviteInfo.has_created) {
                pInfo->timestamp = wlFriendFriendInviteInfo.created;
            }
        } else {
            PB_FREE(pPbLinkItem);
            pPbLinkItem = PB_NULL;
        }
    }

    return pPbLinkItem;
}

PBWeilaMsg* weilapb_decodeGetFriendInviteInfoRsp(const PB_UINT8* pData, PB_UINT32 dataSize) {
    WL_Service_ServiceMessage serviceMessage = WL_Service_ServiceMessage_init_zero;
    pb_istream_t              istream;
    PBWeilaMsg*               pWeilaMsg = PB_ALLOC(sizeof(PBWeilaMsg) + sizeof(PBGetFriendInviteInfoRsp));

    istream = pb_istream_from_buffer(pData, dataSize);

    if (pWeilaMsg) {
        PBFieldData               userInfoListField;
        PBFieldData               friendInfoListField;
        PBGetFriendInviteInfoRsp* pPbGetFriendInviteInfoRsp;
        pWeilaMsg->contentSize    = sizeof(PBGetFriendInviteInfoRsp);
        pPbGetFriendInviteInfoRsp = (PBGetFriendInviteInfoRsp*)pWeilaMsg->pContent;

        weilapb_initDecDataItem(
            &userInfoListField, PB_DATA_TYPE_LINK_SUBMSG, 0, &pPbGetFriendInviteInfoRsp->userInfoList);
        weilapb_setDecCallback(
            &userInfoListField, &serviceMessage.friendMessage.rspGetFriendInviteInfo.userInfos, PB_NULL);
        userInfoListField.decSubMsg = weilapb_decodeSubMsgUserInfo;

        weilapb_initDecDataItem(
            &friendInfoListField, PB_DATA_TYPE_LINK_SUBMSG, 0, &pPbGetFriendInviteInfoRsp->friendInfoList);
        weilapb_setDecCallback(
            &friendInfoListField, &serviceMessage.friendMessage.rspGetFriendInviteInfo.inviteInfos, PB_NULL);
        friendInfoListField.decSubMsg = weilapb_decodeSubMsgFriendInviteInfo;

        if (weilapb_decodeWeilaMsg(pWeilaMsg, &istream, &serviceMessage)) {
            weilapb_addRecyclePointer(pWeilaMsg, RECYCLE_PTR_LINK, &pPbGetFriendInviteInfoRsp->userInfoList);
            weilapb_addRecyclePointer(pWeilaMsg, RECYCLE_PTR_LINK, &pPbGetFriendInviteInfoRsp->friendInfoList);
            if (serviceMessage.friendMessage.rspGetFriendInviteInfo.has_latestUpdated) {
                pPbGetFriendInviteInfoRsp->latestUpdated =
                    serviceMessage.friendMessage.rspGetFriendInviteInfo.latestUpdated;
            }
            return pWeilaMsg;
        }

        weilapb_freePBLinkList(&pPbGetFriendInviteInfoRsp->friendInfoList);
        weilapb_freePBLinkList(&pPbGetFriendInviteInfoRsp->userInfoList);
        weilapb_error(ERR_DECODE, "decode msg data fail");
        PB_FREE(pWeilaMsg);
        pWeilaMsg = PB_NULL;
    } else {
        weilapb_error(ERR_OUT_OF_MEMORY, "allocate weila msg failed");
    }

    return pWeilaMsg;
}

PBWeilaMsg* weilapb_decodeFriendInviteNtf(const PB_UINT8* pData, PB_UINT32 dataSize) {
    WL_Service_ServiceMessage serviceMessage = WL_Service_ServiceMessage_init_zero;
    pb_istream_t              istream;
    PBWeilaMsg*               pWeilaMsg = PB_ALLOC(sizeof(PBWeilaMsg) + sizeof(PBAnswerFriendInviteNtf));

    istream = pb_istream_from_buffer(pData, dataSize);

    if (pWeilaMsg) {
        PBAnswerFriendInviteNtf* pPbAnswerFriendInviteNtf;
        pWeilaMsg->contentSize   = sizeof(PBAnswerFriendInviteNtf);
        pPbAnswerFriendInviteNtf = (PBAnswerFriendInviteNtf*)pWeilaMsg->pContent;

        if (weilapb_decodeWeilaMsg(pWeilaMsg, &istream, &serviceMessage)) {
            if (serviceMessage.friendMessage.ntfAnswerFriendInvite.has_status) {
                pPbAnswerFriendInviteNtf->status = serviceMessage.friendMessage.ntfAnswerFriendInvite.status;
            }

            if (serviceMessage.friendMessage.ntfAnswerFriendInvite.has_inviteeId) {
                pPbAnswerFriendInviteNtf->inviteeId = serviceMessage.friendMessage.ntfAnswerFriendInvite.inviteeId;
            }
            return pWeilaMsg;
        }

        weilapb_error(ERR_DECODE, "decode msg data fail");
        PB_FREE(pWeilaMsg);
        pWeilaMsg = PB_NULL;
    } else {
        weilapb_error(ERR_OUT_OF_MEMORY, "allocate weila msg failed");
    }

    return pWeilaMsg;
}

PBWeilaMsg* weilapb_decodeNewFriendNtf(const PB_UINT8* pData, PB_UINT32 dataSize) {
    WL_Service_ServiceMessage serviceMessage = WL_Service_ServiceMessage_init_zero;
    pb_istream_t              istream;
    PBWeilaMsg*               pWeilaMsg = PB_ALLOC(sizeof(PBWeilaMsg) + sizeof(PBFriendInfo));

    istream = pb_istream_from_buffer(pData, dataSize);

    if (pWeilaMsg) {
        PBFieldData   remarkField;
        PBFieldData   labelField;
        PBFieldData   descField;
        PBFieldData   extentionField;
        PBFriendInfo* pPbFriendInfo;

        pWeilaMsg->contentSize = sizeof(PBFriendInfo);
        pPbFriendInfo          = (PBFriendInfo*)pWeilaMsg->pContent;

        weilapb_initDecDataItem(
            &remarkField, PB_DATA_TYPE_FIXED_SIZE_STRING, MAX_NORMAL_STRING_LEN, pPbFriendInfo->remark);
        weilapb_setDecCallback(&remarkField, &serviceMessage.friendMessage.ntfNewFriend.friendInfo.remark, PB_NULL);

        weilapb_initDecDataItem(
            &labelField, PB_DATA_TYPE_FIXED_SIZE_STRING, MAX_SHORT_STRING_LEN, pPbFriendInfo->label);
        weilapb_setDecCallback(&labelField, &serviceMessage.friendMessage.ntfNewFriend.friendInfo.label, PB_NULL);

        weilapb_initDecDataItem(&descField, PB_DATA_TYPE_FIXED_SIZE_STRING, MAX_LONG_STRING_LEN, pPbFriendInfo->desc);
        weilapb_setDecCallback(&descField, &serviceMessage.friendMessage.ntfNewFriend.friendInfo.desc, PB_NULL);

        weilapb_initDecDataItem(
            &extentionField, PB_DATA_TYPE_FIXED_SIZE_STRING, MAX_NORMAL_STRING_LEN, pPbFriendInfo->extension);
        weilapb_setDecCallback(
            &extentionField, &serviceMessage.friendMessage.ntfNewFriend.friendInfo.extension, PB_NULL);

        if (weilapb_decodeWeilaMsg(pWeilaMsg, &istream, &serviceMessage)) {
            if (serviceMessage.friendMessage.ntfNewFriend.friendInfo.has_userId) {
                pPbFriendInfo->userId = serviceMessage.friendMessage.ntfNewFriend.friendInfo.userId;
            }

            if (serviceMessage.friendMessage.ntfNewFriend.friendInfo.has_tts) {
                pPbFriendInfo->tts = serviceMessage.friendMessage.ntfNewFriend.friendInfo.tts;
            }

            if (serviceMessage.friendMessage.ntfNewFriend.friendInfo.has_status) {
                pPbFriendInfo->status = serviceMessage.friendMessage.ntfNewFriend.friendInfo.status;
            }

            if (serviceMessage.friendMessage.ntfNewFriend.friendInfo.has_locationShare) {
                pPbFriendInfo->locationShared = serviceMessage.friendMessage.ntfNewFriend.friendInfo.locationShare;
            }

            if (serviceMessage.friendMessage.ntfNewFriend.friendInfo.has_shieldStatus) {
                pPbFriendInfo->recvStatus = serviceMessage.friendMessage.ntfNewFriend.friendInfo.shieldStatus;
            }

            return pWeilaMsg;
        }

        weilapb_error(ERR_DECODE, "decode msg data fail");
        PB_FREE(pWeilaMsg);
        pWeilaMsg = PB_NULL;
    } else {
        weilapb_error(ERR_OUT_OF_MEMORY, "allocate weila msg failed");
    }

    return pWeilaMsg;
}

PBWeilaMsg* weilapb_decodeDeleteFriendNtf(const PB_UINT8* pData, PB_UINT32 dataSize) {
    WL_Service_ServiceMessage serviceMessage = WL_Service_ServiceMessage_init_zero;
    pb_istream_t              istream;
    PBWeilaMsg*               pWeilaMsg = PB_ALLOC(sizeof(PBWeilaMsg) + sizeof(PB_UINT32));

    istream = pb_istream_from_buffer(pData, dataSize);

    if (pWeilaMsg) {
        pWeilaMsg->contentSize = sizeof(PB_UINT32);
        if (weilapb_decodeWeilaMsg(pWeilaMsg, &istream, &serviceMessage)) {
            PB_UINT32* pUserId = (PB_UINT32*)pWeilaMsg->pContent;
            if (serviceMessage.friendMessage.ntfDeleteFriend.has_userId) {
                *pUserId = serviceMessage.friendMessage.ntfDeleteFriend.userId;
            }
            return pWeilaMsg;
        }

        weilapb_error(ERR_DECODE, "decode msg data fail");
        PB_FREE(pWeilaMsg);
        pWeilaMsg = PB_NULL;
    } else {
        weilapb_error(ERR_OUT_OF_MEMORY, "allocate weila msg failed");
    }

    return pWeilaMsg;
}

PBWeilaMsg* weilapb_decodeGetFriendBlacklistRsp(const PB_UINT8* pData, PB_UINT32 dataSize) {
    WL_Service_ServiceMessage serviceMessage = WL_Service_ServiceMessage_init_zero;
    pb_istream_t              istream;
    PBWeilaMsg*               pWeilaMsg = PB_ALLOC(sizeof(PBWeilaMsg) + sizeof(PBGetFriendBlacklistRsp));

    istream = pb_istream_from_buffer(pData, dataSize);

    if (pWeilaMsg) {
        PBFieldData              userInfoField;
        PBGetFriendBlacklistRsp* pPbGetFriendBlacklistRsp;
        pWeilaMsg->contentSize   = sizeof(PBGetFriendBlacklistRsp);
        pPbGetFriendBlacklistRsp = (PBGetFriendBlacklistRsp*)pWeilaMsg->pContent;

        weilapb_initDecDataItem(&userInfoField, PB_DATA_TYPE_LINK_SUBMSG, 0, pPbGetFriendBlacklistRsp);
        weilapb_setDecCallback(&userInfoField, &serviceMessage.friendMessage.rspGetFriendBlackList.userInfos, PB_NULL);
        userInfoField.decSubMsg = weilapb_decodeSubMsgUserInfo;

        if (weilapb_decodeWeilaMsg(pWeilaMsg, &istream, &serviceMessage)) {
            weilapb_addRecyclePointer(pWeilaMsg, RECYCLE_PTR_LINK, pPbGetFriendBlacklistRsp);
            return pWeilaMsg;
        }

        weilapb_freePBLinkList(pPbGetFriendBlacklistRsp);
        weilapb_error(ERR_DECODE, "decode msg data fail");
        PB_FREE(pWeilaMsg);
        pWeilaMsg = PB_NULL;
    } else {
        weilapb_error(ERR_OUT_OF_MEMORY, "allocate weila msg failed");
    }

    return pWeilaMsg;
}

PBWeilaMsg* weilapb_decodeGetFriendOnlineRsp(const PB_UINT8* pData, PB_UINT32 dataSize) {
    WL_Service_ServiceMessage serviceMessage = WL_Service_ServiceMessage_init_zero;
    pb_istream_t              istream;
    PBWeilaMsg*               pWeilaMsg = PB_NULL;
    PB_UINT32*                pArray;

    istream = pb_istream_from_buffer(pData, dataSize);

    pArray = (PB_UINT32*)PB_ALLOC(sizeof(PB_UINT32) * 20);
    if (pArray) {
        PBFieldData userIdListField;
        PBWeilaMsg  weilaMsg;

        weilapb_initDecDataItem(&userIdListField, PB_DATA_TYPE_ARRAY_UINT32, 20, pArray);
        weilapb_setDecCallback(&userIdListField, &serviceMessage.friendMessage.rspGetOnlineFriend.userIds, PB_NULL);

        memset(&weilaMsg, 0, sizeof(PBWeilaMsg));
        if (weilapb_decodeWeilaMsg(&weilaMsg, &istream, &serviceMessage)) {
            if (serviceMessage.serviceHead.resultCode == 0) {
                pWeilaMsg = (PBWeilaMsg*)PB_ALLOC(sizeof(PBWeilaMsg) + sizeof(PBArray)
                                                  + sizeof(PB_UINT32) * userIdListField.dataSize);
                if (pWeilaMsg) {
                    PBArray* pList;
                    memcpy(pWeilaMsg, &weilaMsg, sizeof(PBWeilaMsg));
                    pWeilaMsg->contentSize = sizeof(PBArray) + sizeof(PB_UINT32) * userIdListField.dataSize;
                    pList                  = (PBArray*)pWeilaMsg->pContent;
                    pList->listCount       = userIdListField.dataSize;
                    pList->arrayType       = PB_DATA_TYPE_ARRAY_UINT32;
                    memcpy(pList->data, userIdListField.pData, sizeof(PB_UINT32) * userIdListField.dataSize);
                    PB_FREE(pArray);
                    return pWeilaMsg;
                } else {
                    weilapb_error(ERR_OUT_OF_MEMORY, "allocate weila msg failed");
                }
            } else {
                pWeilaMsg = (PBWeilaMsg*)PB_ALLOC(sizeof(PBWeilaMsg));
                if (pWeilaMsg) {
                    memcpy(pWeilaMsg, &weilaMsg, sizeof(PBWeilaMsg));
                } else {
                    weilapb_error(ERR_OUT_OF_MEMORY, "allocate weila msg failed");
                }
            }
        } else {
            weilapb_error(ERR_DECODE, "decode msg data fail");
        }
    } else {
        weilapb_error(ERR_DECODE, "decode msg data fail");
    }

    PB_FREE(pArray);
    pWeilaMsg = PB_NULL;

    return pWeilaMsg;
}

PBWeilaMsg* weilapb_decodeAnswerFriendInviteNtf(const PB_UINT8* pData, PB_UINT32 dataSize) {
    WL_Service_ServiceMessage serviceMessage = WL_Service_ServiceMessage_init_zero;
    pb_istream_t              istream;
    PBWeilaMsg*               pWeilaMsg = PB_ALLOC(sizeof(PBWeilaMsg) + sizeof(PBAnswerFriendInviteNtf));

    istream = pb_istream_from_buffer(pData, dataSize);

    if (pWeilaMsg) {
        PBAnswerFriendInviteNtf* pPbAnswerFriendInviteNtf;
        pWeilaMsg->contentSize = sizeof(PBAnswerFriendInviteNtf);

        pPbAnswerFriendInviteNtf = (PBAnswerFriendInviteNtf*)pWeilaMsg->pContent;

        if (weilapb_decodeWeilaMsg(pWeilaMsg, &istream, &serviceMessage)) {
            if (serviceMessage.friendMessage.ntfAnswerFriendInvite.has_inviteeId) {
                pPbAnswerFriendInviteNtf->inviteeId = serviceMessage.friendMessage.ntfAnswerFriendInvite.inviteeId;
            }

            if (serviceMessage.friendMessage.ntfAnswerFriendInvite.has_status) {
                pPbAnswerFriendInviteNtf->status = serviceMessage.friendMessage.ntfAnswerFriendInvite.status;
            }

            return pWeilaMsg;
        }

        weilapb_error(ERR_DECODE, "decode msg data fail");
        PB_FREE(pWeilaMsg);
        pWeilaMsg = PB_NULL;
    } else {
        weilapb_error(ERR_OUT_OF_MEMORY, "allocate weila msg failed");
    }

    return pWeilaMsg;
}

void* weilapb_decodeSubMsgEmbeddedFriendInfo(pb_istream_t* stream, const pb_field_t* field) {
    WL_Friend_EmbeddedFriendInfo wlFriendEmbeddedFriendInfo = WL_Friend_EmbeddedFriendInfo_init_zero;
    PBLinkItem*                  pPbLinkItem                = PB_NULL;
    pPbLinkItem = (PBLinkItem*)PB_ALLOC(sizeof(PBLinkItem) + sizeof(PBFriendEmbeddedInfo));
    if (pPbLinkItem) {
        PBFieldData           name;
        PBFieldData           number;
        PBFriendEmbeddedInfo* pInfo;

        pPbLinkItem->dataSize = sizeof(PBFriendEmbeddedInfo);

        pInfo = (PBFriendEmbeddedInfo*)pPbLinkItem->data;

        weilapb_initDecDataItem(&name, PB_DATA_TYPE_FIXED_SIZE_STRING, MAX_SHORT_STRING_LEN, pInfo->nick);
        weilapb_setDecCallback(&name, &wlFriendEmbeddedFriendInfo.nick, PB_NULL);

        weilapb_initDecDataItem(&number, PB_DATA_TYPE_FIXED_SIZE_STRING, MAX_PHONE_NUM_LEN, pInfo->number);
        weilapb_setDecCallback(&number, &wlFriendEmbeddedFriendInfo.number, PB_NULL);

        if (pb_decode(stream, WL_Friend_EmbeddedFriendInfo_fields, &wlFriendEmbeddedFriendInfo)) {
            if (wlFriendEmbeddedFriendInfo.has_status) {
                pInfo->status = wlFriendEmbeddedFriendInfo.status;
            }
            if (wlFriendEmbeddedFriendInfo.has_tts) {
                pInfo->tts = wlFriendEmbeddedFriendInfo.tts;
            }

            if (wlFriendEmbeddedFriendInfo.has_locationShare) {
                pInfo->locationShared = wlFriendEmbeddedFriendInfo.locationShare;
            }

            if (wlFriendEmbeddedFriendInfo.has_shieldStatus) {
                pInfo->recvStatus = wlFriendEmbeddedFriendInfo.shieldStatus;
            }

            if (wlFriendEmbeddedFriendInfo.has_sex) {
                pInfo->sex = wlFriendEmbeddedFriendInfo.sex;
            }

            if (wlFriendEmbeddedFriendInfo.has_userId) {
                pInfo->userId = wlFriendEmbeddedFriendInfo.userId;
            }
        } else {
            PB_FREE(pPbLinkItem);
            pPbLinkItem = PB_NULL;
        }
    }

    return pPbLinkItem;
}

PBWeilaMsg* weilapb_decodeGetEmbeddedFriendInfoRsp(const PB_UINT8* pData, PB_UINT32 dataSize) {
    WL_Service_ServiceMessage serviceMessage = WL_Service_ServiceMessage_init_zero;
    pb_istream_t              istream;
    PBWeilaMsg*               pWeilaMsg = PB_ALLOC(sizeof(PBWeilaMsg) + sizeof(PBGetEmbeddedFriendInfoRsp));

    istream = pb_istream_from_buffer(pData, dataSize);

    if (pWeilaMsg) {
        PBFieldData                 friendInfoListField;
        PBGetEmbeddedFriendInfoRsp* pGetEmbeddedFriendInfoRsp;
        pWeilaMsg->contentSize = sizeof(PBGetEmbeddedFriendInfoRsp);

        pGetEmbeddedFriendInfoRsp = (PBGetEmbeddedFriendInfoRsp*)pWeilaMsg->pContent;

        weilapb_initDecDataItem(
            &friendInfoListField, PB_DATA_TYPE_LINK_SUBMSG, 0, &pGetEmbeddedFriendInfoRsp->friendInfoList);
        weilapb_setDecCallback(
            &friendInfoListField, &serviceMessage.friendMessage.rspEmbeddedGetFriendInfo.friendInfos, PB_NULL);
        friendInfoListField.decSubMsg = weilapb_decodeSubMsgEmbeddedFriendInfo;

        if (weilapb_decodeWeilaMsg(pWeilaMsg, &istream, &serviceMessage)) {
            weilapb_addRecyclePointer(pWeilaMsg, RECYCLE_PTR_LINK, &pGetEmbeddedFriendInfoRsp->friendInfoList);
            if (serviceMessage.friendMessage.rspEmbeddedGetFriendInfo.has_latestUpdated) {
                pGetEmbeddedFriendInfoRsp->latestUpdated =
                    serviceMessage.friendMessage.rspEmbeddedGetFriendInfo.latestUpdated;
            }
            return pWeilaMsg;
        }

        weilapb_freePBLinkList(&pGetEmbeddedFriendInfoRsp->friendInfoList);
        weilapb_error(ERR_DECODE, "decode msg data fail");
        PB_FREE(pWeilaMsg);
        pWeilaMsg = PB_NULL;
    } else {
        weilapb_error(ERR_OUT_OF_MEMORY, "allocate weila msg failed");
    }

    return pWeilaMsg;
}

PBWeilaMsg*
    weilapb_decodeFriendMsg(PB_INT32 commandId, PB_INT32 commandType, const PB_UINT8* pData, PB_UINT32 dataSize) {
    PBWeilaMsg* pPbWeilaMsg = PB_NULL;

    switch (commandId) {
        case WL_Friend_FriendCommandId_FRIEND_COMMAND_GET_FRIENDINFO: {
            pPbWeilaMsg = weilapb_decodeGetFriendInfoRsp(pData, dataSize);
            if (pPbWeilaMsg) {
                pPbWeilaMsg->message = WL_FRIEND_GET_FRIEND_INFO_MSG;
            }
        } break;

        case WL_Friend_FriendCommandId_FRIEND_COMMAND_GET_FRIEND_USERINFO: {
            pPbWeilaMsg = weilapb_decodeGetFriendUserInfoRsp(pData, dataSize);
            if (pPbWeilaMsg) {
                pPbWeilaMsg->message = WL_FRIEND_GET_FRIEND_USER_INFO_MSG;
            }
        } break;

        case WL_Friend_FriendCommandId_FRIEND_COMMAND_GET_FRIEND_INVITEINFO: {
            pPbWeilaMsg = weilapb_decodeGetFriendInviteInfoRsp(pData, dataSize);
            if (pPbWeilaMsg) {
                pPbWeilaMsg->message = WL_FRIEND_GET_FRIEND_INVITE_INFO_MSG;
            }
        } break;

        case WL_Friend_FriendCommandId_FRIEND_COMMAND_FRIEND_INVITE: {
            if (commandType == WL_Service_CommandType_COMMAND_RESPONSE) {
                pPbWeilaMsg = weilapb_decodeEmptyRsp(pData, dataSize);
            } else {
                pPbWeilaMsg = weilapb_decodeFriendInviteNtf(pData, dataSize);
            }
            if (pPbWeilaMsg) {
                pPbWeilaMsg->message = WL_FRIEND_FRIEND_INVITE_MSG;
            }
        } break;

        case WL_Friend_FriendCommandId_FRIEND_COMMAND_ANSWER_FRIEND_INVITE: {
            if (commandType == WL_Service_CommandType_COMMAND_RESPONSE) {
                pPbWeilaMsg = weilapb_decodeEmptyRsp(pData, dataSize);
            } else {
                pPbWeilaMsg = weilapb_decodeAnswerFriendInviteNtf(pData, dataSize);
            }
            if (pPbWeilaMsg) {
                pPbWeilaMsg->message = WL_FRIEND_ANSWER_FRIEND_INVITE_MSG;
            }
        } break;

        case WL_Friend_FriendCommandId_FRIEND_COMMAND_NEW_FRIEND: {
            if (commandType == WL_Service_CommandType_COMMAND_NOTIFY) {
                pPbWeilaMsg = weilapb_decodeNewFriendNtf(pData, dataSize);
            }
            if (pPbWeilaMsg) {
                pPbWeilaMsg->message = WL_FRIEND_NEW_FRIEND_MSG;
            }
        } break;

        case WL_Friend_FriendCommandId_FRIEND_COMMAND_DELETE_FRIEND: {
            if (commandType == WL_Service_CommandType_COMMAND_RESPONSE) {
                pPbWeilaMsg = weilapb_decodeEmptyRsp(pData, dataSize);
            } else {
                pPbWeilaMsg = weilapb_decodeDeleteFriendNtf(pData, dataSize);
            }
            if (pPbWeilaMsg) {
                pPbWeilaMsg->message = WL_FRIEND_DELETE_FRIEND_MSG;
            }
        } break;

        case WL_Friend_FriendCommandId_FRIEND_COMMAND_CHANGE_FRIENDINFO: {
            pPbWeilaMsg = weilapb_decodeEmptyRsp(pData, dataSize);
            if (pPbWeilaMsg) {
                pPbWeilaMsg->message = WL_FRIEND_CHANGE_FRIEND_INFO_MSG;
            }
        } break;

        case WL_Friend_FriendCommandId_FRIEND_COMMAND_GET_BLACKLIST: {
            pPbWeilaMsg = weilapb_decodeGetFriendBlacklistRsp(pData, dataSize);
            if (pPbWeilaMsg) {
                pPbWeilaMsg->message = WL_FRIEND_GET_BLACKLIST_MSG;
            }
        } break;

        case WL_Friend_FriendCommandId_FRIEND_COMMAND_CHANGE_BLACKLIST: {
            pPbWeilaMsg = weilapb_decodeEmptyRsp(pData, dataSize);
            if (pPbWeilaMsg) {
                pPbWeilaMsg->message = WL_FRIEND_CHANGE_BLACKLIST_MSG;
            }
        } break;

        case WL_Friend_FriendCommandId_FRIEND_COMMAND_GET_ONLINE_FRIEND: {
            pPbWeilaMsg = weilapb_decodeGetFriendOnlineRsp(pData, dataSize);
            if (pPbWeilaMsg) {
                pPbWeilaMsg->message = WL_FRIEND_GET_ONLINE_FRIEND_MSG;
            }
        } break;

        case WL_Friend_FriendCommandId_FRIEND_EMBEDDED_COMMAND_GET_FRIENDINFO: {
            pPbWeilaMsg = weilapb_decodeGetEmbeddedFriendInfoRsp(pData, dataSize);
            if (pPbWeilaMsg) {
                pPbWeilaMsg->message = WL_FRIEND_GET_EMBEDDED_FRIEND_INFOS;
            }
        } break;
    }

    return pPbWeilaMsg;
}
